"""
PDF file parser using PyPDF2
"""
import time
from pathlib import Path
from typing import Union
import logging

try:
    import PyPDF2
except ImportError:
    PyPDF2 = None

from .base import FileParser, ParseResult, FileType

logger = logging.getLogger(__name__)


class PDFParser(FileParser):
    """
    Parser for PDF files using PyPDF2
    """
    
    def __init__(self, max_file_size: int = 100 * 1024 * 1024):
        super().__init__(max_file_size)
        
        if PyPDF2 is None:
            raise ImportError("PyPDF2 is required for PDF parsing. Install with: pip install PyPDF2")
    
    def supports_file_type(self, file_type: FileType) -> bool:
        """Check if parser supports PDF files"""
        return file_type == FileType.PDF
    
    def parse(self, file_path: Union[str, Path]) -> ParseResult:
        """
        Parse PDF file and extract text content
        
        Args:
            file_path: Path to the PDF file
            
        Returns:
            ParseResult with extracted text and metadata
        """
        start_time = time.time()
        file_path = Path(file_path)
        
        # Validate file
        if not self.validate_file(file_path):
            return self.create_error_result("File validation failed", file_path)
        
        try:
            content_parts = []
            metadata = {}
            
            with open(file_path, 'rb') as file:
                pdf_reader = PyPDF2.PdfReader(file)
                
                # Extract metadata
                if pdf_reader.metadata:
                    metadata.update({
                        "title": pdf_reader.metadata.get("/Title", ""),
                        "author": pdf_reader.metadata.get("/Author", ""),
                        "subject": pdf_reader.metadata.get("/Subject", ""),
                        "creator": pdf_reader.metadata.get("/Creator", ""),
                        "producer": pdf_reader.metadata.get("/Producer", ""),
                        "creation_date": str(pdf_reader.metadata.get("/CreationDate", "")),
                        "modification_date": str(pdf_reader.metadata.get("/ModDate", "")),
                    })
                
                # Get number of pages
                num_pages = len(pdf_reader.pages)
                metadata["page_count"] = num_pages
                
                # Extract text from each page
                for page_num in range(num_pages):
                    try:
                        page = pdf_reader.pages[page_num]
                        page_text = page.extract_text()
                        
                        if page_text.strip():
                            # Add page separator for multi-page documents
                            if content_parts:
                                content_parts.append(f"\n\n--- Page {page_num + 1} ---\n\n")
                            content_parts.append(page_text.strip())
                    
                    except Exception as e:
                        logger.warning(f"Error extracting text from page {page_num + 1}: {e}")
                        continue
                
                # Check if PDF is encrypted
                if pdf_reader.is_encrypted:
                    metadata["encrypted"] = True
                    if not content_parts:
                        return self.create_error_result(
                            "PDF is encrypted and could not be decrypted", 
                            file_path
                        )
                else:
                    metadata["encrypted"] = False
            
            # Combine all content
            full_content = "".join(content_parts)
            
            if not full_content.strip():
                return self.create_error_result("No text content found in PDF", file_path)
            
            processing_time = time.time() - start_time
            
            return self.create_success_result(
                content=full_content,
                file_path=file_path,
                file_type=FileType.PDF,
                processing_time=processing_time,
                additional_metadata=metadata
            )
            
        except PyPDF2.errors.PdfReadError as e:
            error_msg = f"PDF read error: {str(e)}"
            logger.error(error_msg)
            return self.create_error_result(error_msg, file_path)
        
        except Exception as e:
            error_msg = f"Unexpected error parsing PDF: {str(e)}"
            logger.error(error_msg)
            return self.create_error_result(error_msg, file_path)
    
    def extract_pages_range(self, file_path: Union[str, Path], start_page: int, end_page: int) -> ParseResult:
        """
        Extract text from a specific range of pages
        
        Args:
            file_path: Path to the PDF file
            start_page: Starting page number (1-indexed)
            end_page: Ending page number (1-indexed, inclusive)
            
        Returns:
            ParseResult with extracted text from specified pages
        """
        start_time = time.time()
        file_path = Path(file_path)
        
        if not self.validate_file(file_path):
            return self.create_error_result("File validation failed", file_path)
        
        try:
            content_parts = []
            
            with open(file_path, 'rb') as file:
                pdf_reader = PyPDF2.PdfReader(file)
                num_pages = len(pdf_reader.pages)
                
                # Validate page range
                if start_page < 1 or end_page > num_pages or start_page > end_page:
                    return self.create_error_result(
                        f"Invalid page range: {start_page}-{end_page} (total pages: {num_pages})",
                        file_path
                    )
                
                # Extract text from specified range (convert to 0-indexed)
                for page_num in range(start_page - 1, end_page):
                    try:
                        page = pdf_reader.pages[page_num]
                        page_text = page.extract_text()
                        
                        if page_text.strip():
                            if content_parts:
                                content_parts.append(f"\n\n--- Page {page_num + 1} ---\n\n")
                            content_parts.append(page_text.strip())
                    
                    except Exception as e:
                        logger.warning(f"Error extracting text from page {page_num + 1}: {e}")
                        continue
            
            full_content = "".join(content_parts)
            
            if not full_content.strip():
                return self.create_error_result(
                    f"No text content found in pages {start_page}-{end_page}",
                    file_path
                )
            
            processing_time = time.time() - start_time
            
            metadata = {
                "extracted_pages": f"{start_page}-{end_page}",
                "total_pages": num_pages
            }
            
            return self.create_success_result(
                content=full_content,
                file_path=file_path,
                file_type=FileType.PDF,
                processing_time=processing_time,
                additional_metadata=metadata
            )
            
        except Exception as e:
            error_msg = f"Error extracting page range: {str(e)}"
            logger.error(error_msg)
            return self.create_error_result(error_msg, file_path)
    
    def get_pdf_info(self, file_path: Union[str, Path]) -> dict:
        """
        Get PDF metadata without extracting content
        
        Args:
            file_path: Path to the PDF file
            
        Returns:
            Dictionary with PDF metadata
        """
        file_path = Path(file_path)
        
        try:
            with open(file_path, 'rb') as file:
                pdf_reader = PyPDF2.PdfReader(file)
                
                info = {
                    "page_count": len(pdf_reader.pages),
                    "encrypted": pdf_reader.is_encrypted,
                }
                
                if pdf_reader.metadata:
                    info.update({
                        "title": pdf_reader.metadata.get("/Title", ""),
                        "author": pdf_reader.metadata.get("/Author", ""),
                        "subject": pdf_reader.metadata.get("/Subject", ""),
                        "creator": pdf_reader.metadata.get("/Creator", ""),
                        "producer": pdf_reader.metadata.get("/Producer", ""),
                        "creation_date": str(pdf_reader.metadata.get("/CreationDate", "")),
                        "modification_date": str(pdf_reader.metadata.get("/ModDate", "")),
                    })
                
                return info
                
        except Exception as e:
            logger.error(f"Error getting PDF info: {e}")
            return {"error": str(e)}